//
//  LSMainVC.m
//  LibraryStorm
//
//  Created by sanghv on 3/21/14.
//  Copyright (c) 2014 3ATeam. All rights reserved.
//

#import "LSMainViewController.h"
#import "LSDetailViewController.h"
#import "LSSearchViewController.h"
#import "LSEpubViewController.h"
#import "LSSettingViewController.h"

#import "LSCoreDataController.h"
#import "LSSyncEngine.h"
#import "LSDownloadManager.h"

#import "BookDetail.h"
#import "BookCollection.h"
#import "BookCategory.h"

#import "LSBookGridCell.h"
#import "LSBookListCell.h"
#import "LSSortTableView.h"

#import "SVPullToRefresh.h"
#import "PBFlatSegmentedControl.h"
#import "CMPopTipView.h"
#import "UIColor+HexString.h"

static NSString * const GridCellIdentifier = @"GridCellId";
static NSString * const ListCellIdentifier = @"ListCellId";
@interface LSMainViewController ()<LSDownloadManagerDelegate, LSSyncEngineDelegate, CMPopTipViewDelegate, UITableViewDelegate>

@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (weak, nonatomic) IBOutlet UICollectionViewFlowLayout *collectionViewFlowLayout;
@property (weak, nonatomic) IBOutlet PBFlatSegmentedControl *segmentedControl;
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong, readwrite) NSMutableArray *books;
@property (nonatomic, strong) NSArray *filterBooks;
@property (nonatomic, getter = isGridLayout) BOOL gridLayout;
@property (nonatomic) LSMenuLeftType menuType;
@property (nonatomic) LSSortType sortType;
@property (nonatomic) LSModeType modeType;
@property (nonatomic, assign) int categoryId;
@property (nonatomic, strong) CMPopTipView *popTipView;
@end

@implementation LSMainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Initialize default value
    self.gridLayout = YES;
    self.menuType = LSMenuLeftCategory;
    self.sortType = LSSortRecent;
    self.modeType = LSModeServer;
    self.categoryId = 0;
    self.books = [NSMutableArray array];
    
    // Do any additional setup after loading the view.
    [self setListBarItem:@[@(BarItemButton_LeftMenu),@(BarItemButton_Sort_Search)]];
    //TODO: Custom background color
    [self.view setBackgroundColor:[UIColor blackColor]];
    [self.collectionView setBackgroundColor:[UIColor whiteColor]];
    // TODO: Load Records From Core Data
    self.managedObjectContext = [[LSCoreDataController sharedInstance] newManagedObjectContext];
    
    [self loadRecordsFromCoreData];
    
    // TODO: Register notification when sync completed
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadRecords:) name:@"LSSyncEngineSyncCompleted" object:nil];
    [[LSSyncEngine sharedEngine] addObserver:self forKeyPath:@"syncInProgress" options:NSKeyValueObservingOptionNew context:nil];
    
    // TODO: Add pull to refresh on top tableView. Update
    __weak LSMainViewController *weakSelf = self;
    [self.collectionView addPullToRefreshWithActionHandler:^{
        [weakSelf updateRecordsLatest];
    }];
    
    // TODO: Add infinite activator on bottom tableView. Load more
    [self.collectionView addInfiniteScrollingWithActionHandler:^{
        [weakSelf loadMoreRecords];
    }];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Update delegate of LSDownloadManager. Because delegate changed when switch many view controller.
    [LSDownloadManager sharedInstance].delegate = self;
    [self.collectionView.collectionViewLayout invalidateLayout];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if (self.popTipView) {
        [self.popTipView dismissAnimated:YES];
        self.popTipView = nil;
    }
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"LSSyncEngineSyncCompleted" object:nil];
    [[LSSyncEngine sharedEngine] removeObserver:self forKeyPath:@"syncInProgress"];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
    if ([[segue identifier] isEqualToString:@"showDetailId"]) {
        LSDetailViewController *detailViewController = [segue destinationViewController];
        if ([sender isKindOfClass:[NSManagedObjectID class]]) {
            detailViewController.managedObjectId = (NSManagedObjectID *)sender;
            [detailViewController setChangeDownloadStatusCompletionBlock:^{
                // Load again records and reload collectionView when user back to main
                [self loadRecordsFromCoreData];
                [self.collectionView reloadData];
            }];
        }
    }else if ([[segue identifier] isEqualToString:kSegueCollectionToEpubReader]) {
        // Present epubViewController. In History tab, user click on book which read before.
        UINavigationController *navigationViewController = [segue destinationViewController];
        if ([navigationViewController.topViewController isKindOfClass:[LSEpubViewController class]]) {
            LSEpubViewController *epubViewController = (LSEpubViewController *)navigationViewController.topViewController;
            if ([sender isKindOfClass:[BookDetail class]]) {
                BookDetail *book = (BookDetail *)sender;
                if (book.downloadStatus.intValue == LSObjectDownloadCompleted && book.bookPath.length > 0) {
                    NSString *documentPath = [kAppDelegate applicationDocumentsDirectory].relativePath;
                    NSString *ebookPath = [documentPath stringByAppendingFormat:@"%@", book.bookPath];
                    epubViewController.filePath = ebookPath;
                }
            }
        }
    }else if ([[segue identifier] isEqualToString:@"showSettingViewId"]) {
        if (IS_DEVICE_IPAD) {
            if ([segue isKindOfClass:[UIStoryboardPopoverSegue class]]) {
                UIPopoverController *popOverController = [(UIStoryboardPopoverSegue*)segue popoverController];
                UINavigationController *navigationViewController = [segue destinationViewController];
                if ([navigationViewController.topViewController isKindOfClass:[LSSettingViewController class]]) {
                    LSSettingViewController *settingViewController = (LSSettingViewController *)navigationViewController.topViewController;
                    settingViewController.popOverController = popOverController;
                }
            }
        }
    }
}

/**
 * Method name: showBookDetail
 * Description: SearchViewController call this method when user didSelectedCell. Talk to mainViewController show BookDetailViewController
 * Parameters: BookId
 */
- (void)showBookDetailWithID:(NSManagedObjectID *)bookId
{
    if (bookId) {
        [self performSegueWithIdentifier:@"showDetailId" sender:bookId];
    }
}

#pragma mark - CollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.filterBooks.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.isGridLayout) {
        // Load Grid Collection Cell
        LSBookGridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:GridCellIdentifier forIndexPath:indexPath];
        
        if (indexPath.row < self.filterBooks.count) {
            BookDetail *book = [self.filterBooks objectAtIndex:indexPath.row];
            // Load content for this cell
            [cell loadContentCell:book atIndexPath:indexPath];
        }
        
        return cell;
    }else {
        // Load List Collection Cell
        LSBookListCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ListCellIdentifier forIndexPath:indexPath];
        
        if (indexPath.row < self.filterBooks.count) {
            BookDetail *book = [self.filterBooks objectAtIndex:indexPath.row];
            // Load content for this cell
            [cell loadContentCell:book atIndexPath:indexPath];
        }
        
        return cell;
    }
}

#pragma mark - CollectionView Delegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row < self.filterBooks.count) {
        BookDetail *book = [self.filterBooks objectAtIndex:indexPath.row];
        if (self.menuType == LSMenuLeftHistories) {
            [self performSegueWithIdentifier:kSegueCollectionToEpubReader sender:book];
        }else {
            [self performSegueWithIdentifier:@"showDetailId" sender:[book objectID]];
        }
        [self.collectionView deselectItemAtIndexPath:indexPath animated:YES];
    }
}

#pragma mark - CollectionView Flow Layout Delegate
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return [self showCollectionViewFlowLayout:Device_Orientation];
}

- (CGSize)showCollectionViewFlowLayout:(UIInterfaceOrientation)toInterfaceOrientation
{
    if (!self.isGridLayout) {
        if (IS_DEVICE_IPAD) {
            if (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) {
                [self collectionviewFlowLayoutWith:0.0f
                         andMinimumLineSpacing:0.0f
                             andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                                   andSizeMake:CGSizeMake(768.0f, 125.0f)];
            }else {
                [self collectionviewFlowLayoutWith:0.0f
                             andMinimumLineSpacing:0.0f
                                 andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                                       andSizeMake:CGSizeMake(1024.0f, 125.0f)];
            }
        }else {
            if (IS_4INCH_SCREEN) {
                if (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) {
                    [self collectionviewFlowLayoutWith:0.0f
                                 andMinimumLineSpacing:0.0f
                                     andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                                           andSizeMake:CGSizeMake(320.0f, 87.0f)];
                } else {
                    [self collectionviewFlowLayoutWith:0.0f
                                 andMinimumLineSpacing:0.0f
                                     andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                                           andSizeMake:CGSizeMake(568.0f, 87.0f)];
                }
            } else {
                if (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) {
                    [self collectionviewFlowLayoutWith:0.0f
                                 andMinimumLineSpacing:0.0f
                                     andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                                           andSizeMake:CGSizeMake(320.0f, 87.0f)];
                } else {
                    [self collectionviewFlowLayoutWith:0.0f
                                 andMinimumLineSpacing:0.0f
                                     andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                                           andSizeMake:CGSizeMake(480.0f, 87.0f)];
                }
            }
        }
    }else {
        if (IS_DEVICE_IPAD) {
            if (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) {
                [self collectionviewFlowLayoutWith:0.0f
                         andMinimumLineSpacing:25.0f
                             andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 35.0f, 0.0f, 35.0f)
                                   andSizeMake:CGSizeMake(150.0f, 225.0f)];
            }else {
                [self collectionviewFlowLayoutWith:0.0f
                             andMinimumLineSpacing:35.0f
                                 andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 62.5f, 0.0f, 62.5f)
                                       andSizeMake:CGSizeMake(150.0f, 225.0f)];
            }
        }else {
            [self collectionviewFlowLayoutWith:0.0f
                     andMinimumLineSpacing:10.0f
                         andEdgeInsetsMake:UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)
                               andSizeMake:CGSizeMake(100.0f, 141.0f)];
        }
    }
    
    return self.collectionViewFlowLayout.itemSize;
}

- (void)collectionviewFlowLayoutWith:(float)minimumInteritemSpacing
               andMinimumLineSpacing:(float)minimumLineSpacing
                   andEdgeInsetsMake:(UIEdgeInsets)edgeInsetsMake
                         andSizeMake:(CGSize)sizeMake {
    [self.collectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
    [self.collectionViewFlowLayout setMinimumInteritemSpacing:minimumInteritemSpacing];
    [self.collectionViewFlowLayout setMinimumLineSpacing:minimumLineSpacing];
    self.collectionViewFlowLayout.sectionInset = edgeInsetsMake;
    [self.collectionViewFlowLayout setItemSize:sizeMake];
}

#pragma mark - Load and Update Records
/**
 * Method name: loadRecordsFromCoreData
 * Description: Get new all records from core data. Method is called when starting load viewController, after sync completed, update successful, load more, select menuLeft to reload data.
 * Parameters: nil
 */
- (void)loadRecordsFromCoreData
{
    // Remove all objects
    if (self.books.count > 0) {
        [self.books removeAllObjects];

    }
    
    NSString *navigationTitle = @"";
    NSPredicate *predicate = nil;
    switch (self.menuType) {
        case LSMenuLeftCategory:
            // Check if user select 1 category from menuLeft.
            // If categoryId is 0 that show all books
            // If categoryId != 0 then set predicate to filter books
            if (self.categoryId > 0 && self.categoryManagedObjectID) {
                BookCategory *category = (BookCategory *)[self.managedObjectContext objectWithID:self.categoryManagedObjectID];
                [self.books addObjectsFromArray:category.listOfBooks.allObjects];
                navigationTitle = category.name;
            }else if (self.categoryId == 0) {
                [self.books addObjectsFromArray:[BookDetail getAllObjectsInContext:self.managedObjectContext resetContext:YES fetchLimit:0]];
                navigationTitle = NSLocalizedString(@"AllCategory", nil);
            }
            break;
            
        case LSMenuLeftFavorites:
            // Get books which user favorited
            navigationTitle = NSLocalizedString(@"Favorites", nil);
            predicate = [NSPredicate predicateWithFormat:@"favorited == YES"];
            [self.books addObjectsFromArray:[BookDetail getAllObjectsInContext:self.managedObjectContext withSortDescriptor:nil withPredicate:predicate resetContext:YES fetchLimit:0]];
            break;
            
        case LSMenuLeftCollections:
            // Get books which user add collection
            if (self.collectionManagedObjectID) {
                BookCollection *collection = (BookCollection *)[self.managedObjectContext objectWithID:self.collectionManagedObjectID];
                navigationTitle = collection.name;
                [self.books addObjectsFromArray:collection.listOfBooks.allObjects];
            }else {
                [self setTitle:NSLocalizedString(@"Collections", nil)];
            }
            break;
            
        case LSMenuLeftHistories:
            // Show books which user read before
            navigationTitle = NSLocalizedString(@"History", nil);
            predicate = [NSPredicate predicateWithFormat:@"recentAt != nil"];
            [self.books addObjectsFromArray:[BookDetail getAllObjectsInContext:self.managedObjectContext withSortDescriptor:nil withPredicate:predicate resetContext:YES fetchLimit:0]];
            break;
            
        case LSMenuLeftDownloads:
            // Show books which downloading, pause, failed
            navigationTitle = NSLocalizedString(@"Downloads", nil);
            predicate = [NSPredicate predicateWithFormat:@"downloadStatus != %d AND downloadStatus != %d", LSObjectDownloadNone, LSObjectDownloadCompleted];
            [self.books addObjectsFromArray:[BookDetail getAllObjectsInContext:self.managedObjectContext withSortDescriptor:nil withPredicate:predicate resetContext:YES fetchLimit:0]];
            break;
            
        default:
            break;
    }
    
    [self setTitle:navigationTitle];
    
    // Sort book by sortType
    NSSortDescriptor *sortDescriptor = nil;
    switch (self.sortType) {
        case LSSortRecent:
            sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"recentAt" ascending:NO];
            break;
        case LSSortTitle:
            sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
            break;
        case LSSortAuthor:
            sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"author" ascending:YES];
            break;
            
        default:
            break;
    }
    
    // Filter book by modeType
    if (self.modeType == LSModeClient) {
        predicate = [NSPredicate predicateWithFormat:@"downloadStatus == %d && bookPath != nil", LSObjectDownloadCompleted];
        NSArray *tempBooks = [self.books filteredArrayUsingPredicate:predicate];
        self.filterBooks = [tempBooks sortedArrayUsingDescriptors:@[sortDescriptor]];
    }else {
        self.filterBooks = [self.books sortedArrayUsingDescriptors:@[sortDescriptor]];
    }
}

/**
 * Method name: Notification Observe
 * Description: Catch notification when sync completed
 * Parameters: nil
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"syncInProgress"]) {
        if (![LSSyncEngine sharedEngine].syncInProgress) {
            
        }
    }
}

- (void)reloadRecords:(NSNotification *)note
{
    if ([[note object] isEqualToString:BOOK_DETAIL]) {
        [self loadRecordsFromCoreData];
        [self.collectionView reloadData];
    }
}

/**
 * Method name: updateRecordsLatest
 * Description: When user scroll to top to start update new book from service.
 * Parameters: nil
 */
- (void)updateRecordsLatest
{
    // Only update if on category. Not favorite, history tab ...
    if (self.menuType == LSMenuLeftCategory && self.modeType == LSModeServer) {
        if (![kAppDelegate limitRequestForDay]) {
            [[LSSyncEngine sharedEngine] syncDataForRegisteredObject:BOOK_DETAIL toUseUpdatedAtDate:YES toDeleteLocalRecords:NO withCategoryType:self.categoryId limitRecords:LIMIT_MAX_RECORDS skipOverRecords:0];
            [LSSyncEngine sharedEngine].delegate = self;
        }else {
            __weak LSMainViewController *weakSelf = self;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [weakSelf.collectionView.pullToRefreshView stopAnimating];
            });
        }
    }else {
        __weak LSMainViewController *weakSelf = self;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.collectionView.pullToRefreshView stopAnimating];
        });
    }
}

/**
 * Method name: loadMoreRecords
 * Description: When user scroll to bottom to start load more old book from service.
 * Parameters: nil
 */
- (void)loadMoreRecords
{
    // Only update if on category. Not favorite, history tab ...
    if (self.menuType == LSMenuLeftCategory && self.modeType == LSModeServer) {
        if (![kAppDelegate limitRequestForDay]) {
            [[LSSyncEngine sharedEngine] syncDataForRegisteredObject:BOOK_DETAIL toUseUpdatedAtDate:NO toDeleteLocalRecords:NO withCategoryType:self.categoryId limitRecords:LIMIT_MAX_RECORDS skipOverRecords:(int)self.filterBooks.count];
            [LSSyncEngine sharedEngine].delegate = self;
        }else {
            __weak LSMainViewController *weakSelf = self;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [weakSelf.collectionView.infiniteScrollingView stopAnimating];
            });
        }
    }else {
        __weak LSMainViewController *weakSelf = self;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.collectionView.infiniteScrollingView stopAnimating];
        });
    }
}

#pragma mark - Rotate Orientation
/**
 * Method name: willRotateToInterfaceOrientation:duration
 * Description: Delegate called when user rotate device. When rotate that call collectionLayout to calculate own layout.
 * Parameters: UIInterfaceOrientation, NSTimeInterval
 */
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [self.collectionView.collectionViewLayout invalidateLayout];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    //Fix orientation of popTipView
    if (self.popTipView) {
        id targetObject = self.popTipView.targetObject;
        [self.popTipView dismissAnimated:NO];
        
        if ([targetObject isKindOfClass:[UIButton class]]) {
            UIButton *button = (UIButton *)targetObject;
            [self.popTipView presentPointingAtView:button inView:self.view animated:NO];
        }
        else {
            UIBarButtonItem *barButtonItem = (UIBarButtonItem *)targetObject;
            [self.popTipView presentPointingAtBarButtonItem:barButtonItem animated:NO];
        }
    }
}

#pragma mark - Target Action
/**
 * Method name: changeCollectionLayout
 * Description: Change collection layout from grid to list and vice versa.
 * Parameters: UIButton
 */
- (IBAction)changeCollectionLayout:(UIButton *)sender
{
    self.gridLayout = !self.isGridLayout;
    if (self.isGridLayout) {
        [sender setImage:LIST_IMAGE forState:UIControlStateNormal];
    }else {
        [sender setImage:GRID_IMAGE forState:UIControlStateNormal];
    }
    
    [self.collectionView reloadData];
}

/**
 * Method name: searchButtonPress
 * Description: Present SearchViewController (iPhone), popOver (iPad)
 * Parameters: UIButton
 */
- (void)searchButtonPress:(id)sender
{
    [self performSegueWithIdentifier:@"showSearchId" sender:sender];
}

/**
 * Method name: changeBookStatus
 * Description: Show all book or book which downloaded on device
 * Parameters: UISegmentedControl
 */
- (IBAction)changeBookStatus:(UISegmentedControl *)sender
{
    self.modeType = (LSModeType)sender.selectedSegmentIndex;
    [self loadRecordsFromCoreData];
    [self.collectionView reloadData];
}

/**
 * Method name: sortButtonPress
 * Description: Change sort type of list books. Show popOver view that user select type.
 * Parameters: UIBarButtonItem
 */
- (void)sortButtonPress:(UIButton *)sender
{
    if (!self.popTipView) {
        LSSortTableView *sortTableView = [[LSSortTableView alloc] initWithFrame:CGRectMake(0, 0, 200, 130)];
        sortTableView.items = @[NSLocalizedString(@"Recent", nil),NSLocalizedString(@"Title", nil),NSLocalizedString(@"Author", nil),];
        sortTableView.delegate = self;
        sortTableView.dataSource = sortTableView;
        sortTableView.selectedIndex = self.sortType;
        sortTableView.showsHorizontalScrollIndicator = NO;
        sortTableView.showsVerticalScrollIndicator = NO;
        sortTableView.scrollEnabled = NO;
        
        self.popTipView = [[CMPopTipView alloc] initWithCustomView:sortTableView];
        self.popTipView.delegate = self;
        self.popTipView.backgroundColor = [UIColor whiteColor];
        self.popTipView.dismissTapAnywhere = YES;
        self.popTipView.cornerRadius = 5.0;
        self.popTipView.hasShadow = NO;
        self.popTipView.has3DStyle = NO;
        self.popTipView.hasGradientBackground = NO;
        self.popTipView.borderColor = [UIColor colorWithHexString:Color_Orange_View];
        [self.popTipView presentPointingAtView:sender inView:self.view animated:YES];
    }else {
        [self.popTipView dismissAnimated:YES];
        self.popTipView = nil;
    }
}

// Override method Because to dismiss popTipView if it visible.
- (void)leftDrawerButtonPress:(id)sender
{
    [super leftDrawerButtonPress:sender];
    if (self.popTipView) {
        [self.popTipView dismissAnimated:YES];
        self.popTipView = nil;
    }
}

- (IBAction)showSettingView:(id)sender
{
    [self performSegueWithIdentifier:@"showSettingViewId" sender:sender];
}

#pragma mark - Menu Left Action
/**
 * Method name: showListBook:withCategoryType
 * Description: Reload data when user click cell on menuLeft.
 * Parameters: LSMenuLeftType, categoryId
 */
- (void)showListBook:(LSMenuLeftType)menuType withCategoryType:(int)categoryId
{
    [LSDownloadManager sharedInstance].delegate = self;
    self.menuType = menuType;
    self.categoryId = categoryId;
    
    [self loadRecordsFromCoreData];
    [self.collectionView reloadData];
}

#pragma mark - PopTipView Delegate
/**
 * Method name: popTipViewWasDismissedByUser
 * Description: PopTipView Delegate.
 * Parameters: CMPopTipView
 */
- (void)popTipViewWasDismissedByUser:(CMPopTipView *)popTipView
{
    if (self.popTipView) {
        [self.popTipView dismissAnimated:YES];
        self.popTipView = nil;
    }
}

#pragma mark - Table view Delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.popTipView) {
        [self.popTipView dismissAnimated:YES];
        self.popTipView = nil;
        // Get sortType from selectedIndex.
        self.sortType = (LSSortType)indexPath.row;
        [self loadRecordsFromCoreData];
        [self.collectionView reloadData];
    }
}
#pragma mark - Download Manager Delegate
/**
 * Method name: DownloadManager
 * Description: Check status of download. 3 state: completed, failed, processing.
 * Parameters: LSDownloadManager, AFHTTPRequestOperation
 */
- (void)downloadManager:(LSDownloadManager *)downloadManager operationCompleted:(AFHTTPRequestOperation *)operation
{
    [self changeDownloadStatus:LSObjectDownloadCompleted withOperation:operation];
    if (self.menuType == LSMenuLeftDownloads) {
        
    }
}

- (void)downloadManager:(LSDownloadManager *)downloadManager operationFailed:(AFHTTPRequestOperation *)operation
{
    LSObjectDownloadStatus downloadStatus = LSObjectDownloadFailed;
    if (operation.error.code == 516) {
        // Error File isExist
        downloadStatus = LSObjectDownloadCompleted;
    }
    [self changeDownloadStatus:downloadStatus withOperation:operation];
    if (self.menuType == LSMenuLeftDownloads) {
        
    }
}

- (void)downloadManager:(LSDownloadManager *)downloadManager operationStateUpdate:(AFDownloadRequestOperation *)operation downloadProgress:(float)progress
{
    if (self.menuType == LSMenuLeftDownloads) {
        
    }
}

/**
 * Method name: changeDownloadStatus:withOperation
 * Description: Update status of book which downloaded, set bookPath. Then update collectionView
 * Parameters: LSObjectDownloadStatus, AFHTTPRequestOperation
 */
- (void)changeDownloadStatus:(LSObjectDownloadStatus)downloadStatus withOperation:(AFHTTPRequestOperation *)operation
{
    if (operation) {
        NSHTTPURLResponse *urlResponse = operation.response;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"downloadLink = %@", urlResponse.URL.absoluteString];
        BookDetail *book = (BookDetail *)[BookDetail findObjectInContext:self.managedObjectContext withPredicate:predicate];
        if (book) {
            [book setObjectInContext:self.managedObjectContext withValue:[NSNumber numberWithInt:downloadStatus] forKey:@"downloadStatus"];
            if ([operation isKindOfClass:[AFDownloadRequestOperation class]]) {
                NSString *targetPath = [(AFDownloadRequestOperation *)operation targetPath];
                NSString *documentPath = [kAppDelegate applicationDocumentsDirectory].relativePath;
                if ([targetPath rangeOfString:documentPath].location != NSNotFound) {
                    NSString *bookPath = [targetPath stringByReplacingOccurrencesOfString:documentPath withString:@""];
                    [book setObjectInContext:self.managedObjectContext withValue:bookPath forKey:@"bookPath"];
                }
            }
            
            [self loadRecordsFromCoreData];
            [self.collectionView reloadData];
        }
    }
}

#pragma mark - Sync Enigne Deleta
/**
 * Method name: Sync Engine
 * Description: Update new book, loadmore old book. Not use to sync data when start or application active.
 * Parameters: LSSyncEngine, ClassName, useUpdatedAtDate
 */
- (void)syncEngine:(LSSyncEngine *)syncEngine forRegisteredObject:(NSString *)className toUseUpdatedAtDate:(BOOL)useUpdatedAtDate
{
    if ([className isEqualToString:BOOK_DETAIL]) {
        [self loadRecordsFromCoreData];
        [self.collectionView reloadData];
        
        __weak LSMainViewController *weakSelf = self;
        if (useUpdatedAtDate) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [weakSelf.collectionView.pullToRefreshView stopAnimating];
            });
        }else {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [weakSelf.collectionView.infiniteScrollingView stopAnimating];
            });
        }
        
        [kAppDelegate increaseCountOfRequestForDay];
    }
}

- (void)syncEngine:(LSSyncEngine *)syncEngine withError:(NSError *)error toUseUpdatedAtDate:(BOOL)useUpdatedAtDate
{
    __weak LSMainViewController *weakSelf = self;
    if (useUpdatedAtDate) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.collectionView.pullToRefreshView stopAnimating];
        });
    }else {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf.collectionView.infiniteScrollingView stopAnimating];
        });
    }
}
@end
